﻿#include "FITKAbaqusAdaptorSurface.h"
#include "InpKeyLineSpliter.h"
#include "FITKAbaqusINPReader.h"
#include "FITKAbaqusINPWriter.h"
#include "FITK_Kernel/FITKCore/FITKEnumTransformer.hpp"
#include "FITK_Interface/FITKInterfaceModel/FITKComponentManager.h"
#include "FITK_Interface/FITKInterfaceModel/FITKAbstractAssInstance.h"
#include "FITK_Interface/FITKInterfaceStructural/FITKAbaSurfaceLabel.h"
#include "FITK_Interface/FITKInterfaceModel/FITKMeshSurface.h"
#include "FITK_Interface/FITKInterfaceModel/FITKMeshSurfaceNode.h"
#include "FITK_Interface/FITKInterfaceModel/FITKMeshSurfaceElement.h"
#include "FITK_Interface/FITKInterfaceStructural/FITKAbaAssembly.h"
#include "FITK_Component/FITKAbaqusData/FITKAbaqusPart.h"
#include "FITK_Component/FITKAbaqusData/FITKDataCase.h"
#include "FITK_Kernel/FITKAppFramework/FITKMessage.h"
#include <QTextStream>
#include <QList>
#include <QHash>
#include <QDebug>

namespace IO
{
    QString FITKAbaqusAdaptorSurface::getAdaptorClass()
    {
        return "FITKAbaqusAdaptorSurface";
    }

    bool FITKAbaqusAdaptorSurface::adaptR()
    {
        Interface::FITKMeshSurface* surfaceData = dynamic_cast<Interface::FITKMeshSurface*>(_dataObj);
        if (!surfaceData || !_reader || !_caseData) return false;
        //回退一行，处理关键字信息
        _reader->backLine();

        bool readOK = false;
        QString line = _reader->readLine();
        //处理关键字数据
        InpKeyLineSpliter spl(line, _reader);
        if (!spl.hasKey("name"))
        {
            return false;
        }
        QString name = spl["name"];
        surfaceData->setDataObjectName(name);

        if (spl.hasKey("internal"))
            surfaceData->isInternal(true);
        //获取类型
        Interface::FITKMeshSurface::MeshSurfaceType type = surfaceData->getMeshSurfaceType();
        if (type == Interface::MeshSurfaceType::SurEle)
        {
            readOK = this->elementTypeR();
        }
        else if (type == Interface::MeshSurfaceType::SurNode)
        {
            readOK = this->nodeTypeR();
        }
        return readOK;
    }

    bool FITKAbaqusAdaptorSurface::adaptW()
    {
        //获取数据
        Interface::FITKMeshSurface* surfaceData = dynamic_cast<Interface::FITKMeshSurface*>(_dataObj);
        if (!surfaceData || !_writer || !_caseData) return false;
        bool writeOK = false;
        //获取类型，写出不同类型的格式
        Interface::FITKMeshSurface::MeshSurfaceType type = surfaceData->getMeshSurfaceType();
        if (type == Interface::FITKMeshSurface::MeshSurfaceType::SurEle)
        {
            writeOK = this->elementTypeW();
        }
        else if (type == Interface::FITKMeshSurface::MeshSurfaceType::SurNode)
        {
            writeOK = this->nodeTypeW();
        }
        return writeOK;
    }

    void FITKAbaqusAdaptorSurface::setCaseData(AbaqusData::FITKDataCase* caseData)
    {
        _caseData = caseData;
    }

    bool FITKAbaqusAdaptorSurface::elementTypeR()
    {
        Interface::FITKMeshSurfaceElement* surfaceData = dynamic_cast<Interface::FITKMeshSurfaceElement*>(_dataObj);
        if (!surfaceData || !_reader || !_caseData) return false;
        Core::FITKEnumTransfer<Interface::FITKAbaSurfaceLabel::AbaSurfLabel> surfLabel;
        //用于记录是否有面
        int ok = false;
        QString line;
        while (!_reader->atEnd())
        {
            line = _reader->readLine();
            if (line.startsWith('*'))
                break;
            //获取集合名称和面的标识
            QStringList strList = line.split(',');
            if (strList.size() != 2) return false;
            //通过集合名称获取集合数据和模型id
            int modelId = -1;
            Interface::FITKModelSet* setData = this->getSetByName(strList.at(0).trimmed(), modelId);
            if (!this->isContainSetType(setData, Interface::FITKModelEnum::FITKModelSetType::FMSElem) || modelId == -1)return false;
            //获取面标识
            int elemType = -1;
            if (!strList.at(1).trimmed().isEmpty())
            {
                bool isValid = false;
                Interface::FITKAbaSurfaceLabel::AbaSurfLabel elType = surfLabel.fromString(strList.at(1).trimmed(), isValid);
                if (!isValid) return false;
                elemType = elType;
            }
            surfaceData->addMeshSet(modelId, setData->getDataObjectID(), elemType);
            ok = true;
        }
        return ok;
    }

    bool FITKAbaqusAdaptorSurface::nodeTypeR()
    {
        Interface::FITKMeshSurfaceNode* surfaceData = dynamic_cast<Interface::FITKMeshSurfaceNode*>(_dataObj);
        if (!surfaceData || !_reader || !_caseData) return false;
        //用于记录是否有面
        int readok = false;
        QString line;
        while (!_reader->atEnd())
        {
            line = _reader->readLine();
            if (line.startsWith('*'))
                break;
            //获取setName和加权因子
            QStringList strList = line.split(',');
            if (strList.isEmpty() || strList.size() > 2) return false;
            //通过集合名称获取集合数据和模型id
            int modelId = -1;
            Interface::FITKModelSet* setData = this->getSetByName(strList.at(0).trimmed(), modelId);
            if (!this->isContainSetType(setData, Interface::FITKModelEnum::FITKModelSetType::FMSNode) || modelId == -1)return false;
            //获取加权因子
            double value = 0.0;
            if (strList.size() > 1)
            {
                bool ok = false;
                value = strList.at(1).trimmed().toDouble(&ok);
                if (!ok) return false;
            }
            surfaceData->addMeshSet(modelId, setData->getDataObjectID(), value);
            readok = true;
        }
        return readok;
    }

    bool FITKAbaqusAdaptorSurface::elementTypeW()
    {
        Interface::FITKMeshSurfaceElement* surfaceData = dynamic_cast<Interface::FITKMeshSurfaceElement*>(_dataObj);
        if (!surfaceData || !_writer || !_caseData) return false;
        //写出*surface
        QTextStream* stream = _writer->getStream();
        QString surfName = surfaceData->getDataObjectName();
        surfName = surfName.contains(' ') ? QString("\"%1\"").arg(surfName) : surfName;
        QString writeLine = QString("*Surface, type=ELEMENT, name=%1").arg(surfName);
        if (surfaceData->isInternal())
            writeLine += ", internal";
        *stream << writeLine << endl;
        //写出surface的数据 单元集, 面标识
        writeLine.clear();
        Core::FITKEnumTransfer<Interface::FITKAbaSurfaceLabel::AbaSurfLabel> surfLabel;
        int count = surfaceData->getMeshSetCount();
        //记录set与面索引的映射
        QHash<QString, QList<int>> setPolygonIndexes;
        for (int i = 0; i < count; ++i)
        {
            bool ok = false;
            Interface::FITKModelSet* set = surfaceData->getMeshSetAt(i);
            auto mode = surfaceData->getModelAt(i);
            if (!set || !mode)continue;
            //获取集合id
            QString setName = set->getDataObjectName();
            setName = setName.contains(' ') ? QString("\"%1\"").arg(setName) : setName;
            //获取面的索引
            int polygonIndex = surfaceData->getSurfaceIndexAt(i);
            //判断是否在set与面索引的映射里面
            if (setPolygonIndexes.contains(setName) && setPolygonIndexes.value(setName).contains(polygonIndex))continue;
            //判断集合与表面的隶属关系来写出集合
            if (set->getAbstractModel() && mode->getAbsModelType() == Interface::FITKModelEnum::AbsModelType::AssInstance && set->getAbsModelID() != mode->getDataObjectID())
            {
                QString name = mode->getDataObjectName();
                name = name.contains(' ') ? QString("\"%1\"").arg(name) : name;
                setName = name + "." + setName;
            }
            //写出面的索引
            QString faceFlag{};
            if (polygonIndex != -1)
                faceFlag = surfLabel.toStrting((Interface::FITKAbaSurfaceLabel::AbaSurfLabel)polygonIndex, ok);
            else
                ok = true;
            if (!ok)
                continue;
            writeLine = setName + ", " + faceFlag;
            *stream << writeLine << endl;
            //存储set与面索引到映射
            if (setPolygonIndexes.contains(setName))
                setPolygonIndexes[setName].append(polygonIndex);
            else
                setPolygonIndexes.insert(setName, QList<int>() << polygonIndex);
        }
        return true;
    }

    bool FITKAbaqusAdaptorSurface::nodeTypeW()
    {
        Interface::FITKMeshSurfaceNode* surfaceData = dynamic_cast<Interface::FITKMeshSurfaceNode*>(_dataObj);
        if (!surfaceData || !_writer || !_caseData) return false;
        //写出*surface
        QTextStream* stream = _writer->getStream();
        QString surfName = surfaceData->getDataObjectName();
        surfName = surfName.contains(' ') ? QString("\"%1\"").arg(surfName) : surfName;
        QString writeLine = QString("*Surface, type=NODE, name=%1").arg(surfName);
        if (surfaceData->isInternal())
            writeLine += ", internal";
        *stream << writeLine << endl;
        //写出surface的数据 单元集, 面标识
        writeLine.clear();
        int count = surfaceData->getMeshSetCount();
        //记录set与面数值的映射
        QHash<QString, QList<double>> setPolygonIndexes;
        for (int i = 0; i < count; ++i)
        {
            auto d = surfaceData->getMeshSetAt(i);
            Interface::FITKModelSet* set = dynamic_cast<Interface::FITKModelSet*>(d);
            auto mode = surfaceData->getModelAt(i);
            if (!set || !mode)continue;
            QString setName = set->getDataObjectName();
            setName = setName.contains(' ') ? QString("\"%1\"").arg(setName) : setName;
            //获取面的数值
            double polygonValue = surfaceData->getValueAt(i);
            //判断是否在set与面数值的映射里面
            bool isExist = false;
            if (setPolygonIndexes.contains(setName))
            {
                QList<double> valueList = setPolygonIndexes.value(setName);
                for (double value : valueList)
                {
                    if (fabsl(value - polygonValue) < 1e-16)
                    {
                        isExist = true;
                        break;
                    }
                }
            }
            if (isExist)continue;
            //判断集合与表面的隶属关系来写出集合
            if (set->getAbstractModel() && mode->getAbsModelType() == Interface::FITKModelEnum::AbsModelType::AssInstance && set->getAbsModelID() != mode->getDataObjectID())
            {
                QString name = mode->getDataObjectName();
                name = name.contains(' ') ? QString("\"%1\"").arg(name) : name;
                setName = name + "." + setName;
            }
            QString value = _writer->double2String(surfaceData->getValueAt(i), 9);
            if (fabsl(surfaceData->getValueAt(i)) < 1e-15)
                writeLine = setName;
            else
                writeLine = setName + ", " + value;
            *stream << writeLine << endl;
            //存储set与面索引到映射
            if (setPolygonIndexes.contains(setName))
                setPolygonIndexes[setName].append(polygonValue);
            else
                setPolygonIndexes.insert(setName, QList<double>() << polygonValue);
        }
        return true;
    }

    Interface::FITKModelSet* FITKAbaqusAdaptorSurface::getSetByName(QString setName, int& modelId)
    {
        //获取表面
        Interface::FITKMeshSurface* surfaceData = dynamic_cast<Interface::FITKMeshSurface*>(_dataObj);
        if (!surfaceData || !_caseData)return nullptr;
        //获取表面所属模型
        Interface::FITKAbstractModel* model = surfaceData->getAbstractModel();
        if (!model)return nullptr;
        //获取模型id
        modelId = model->getDataObjectID();
        //通过模型获取集合表面管理器
        Interface::FITKComponentManager* setSurfManager = nullptr;
        if (model->getAbsModelType() == Interface::FITKModelEnum::AbsModelType::AMTMIX)
        {
            //part
            AbaqusData::FITKAbaqusPart* partData = dynamic_cast<AbaqusData::FITKAbaqusPart*>(model);
            if (!partData)return nullptr;
            setSurfManager = partData->getComponentManager();
        }
        else if (model->getAbsModelType() == Interface::FITKModelEnum::AbsModelType::Assembly)
        {
            //assembly
            Interface::FITKAbaAssembly* assemblyData = dynamic_cast<Interface::FITKAbaAssembly*>(model);
            if (!assemblyData)return nullptr;
            setSurfManager = assemblyData->getComponentManager();
        }
        if (!setSurfManager)return nullptr;
        //获取集合链表-是复合集合就获取复合集合，不是复合集合就获取本身
        QList<Interface::FITKModelSet*> setDataList = setSurfManager->getAllSet(false);
        //根据名称获取集合
        for (auto setData : setDataList)
        {
            if (setData->getDataObjectName() == setName)
                return setData;
        }
        //*.*类型的名称集合数据获取
        QStringList str = setName.split('.');
        if (str.size() != 2)return nullptr;
        //获取instance的名称
        QString instanceName = str.at(0);
        //获取集合的名称
        setName = str.at(1);
        if (instanceName.isEmpty())return nullptr;
        //获取装配
        Interface::FITKAbaAssembly* assemblyData = _caseData->getAssembly();
        if (!assemblyData)return nullptr;
        //通过instance的名称获取instance->instanceID
        Interface::FITKAbstractAssInstance* instanceData = assemblyData->getDataByName(instanceName);
        if (!instanceData)return nullptr;
        //从新获取模型id->instanceId
        modelId = instanceData->getDataObjectID();
        //通过instanceData获取模型partData
        AbaqusData::FITKAbaqusPart* partData = dynamic_cast<AbaqusData::FITKAbaqusPart*>(instanceData->getModel());
        if (!partData)return nullptr;
        //再次获取partData下的集合表面管理器
        setSurfManager = partData->getComponentManager();
        if (!setSurfManager)return nullptr;
        //获取集合链表-是复合集合就获取复合集合，不是复合集合就获取本身
        setDataList = setSurfManager->getAllSet(false);
        //根据名称获取集合
        for (auto setData : setDataList)
        {
            if (setData->getDataObjectName() == setName)
                return setData;
        }
        return nullptr;
    }

    bool FITKAbaqusAdaptorSurface::isContainSetType(Interface::FITKModelSet* setData, int type)
    {
        if (!setData)return false;
        //获取需要包含的集合类型
        Interface::FITKModelEnum::FITKModelSetType setType = (Interface::FITKModelEnum::FITKModelSetType)(type);
        //获取集合是否为复合集合
        if (!setData->isCombination())
        {
            //不是复合集合就直接判断本身类型是否是setType集合类型
            if (setData->getModelSetType() == setType)
                return true;
            return false;
        }
        //获取复合集合里的子集合数量
        int count = setData->getDataCount();
        for (int i = 0; i < count; ++i)
        {
            //是复合集合就需要判断子集合是否包含setType集合类型
            Interface::FITKModelSet* childSetData = setData->getDataByIndex(i);
            if (childSetData && childSetData->getModelSetType() == setType)
                return true;
        }
        return false;
    }
}
